﻿using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Threading;

namespace DimensionsHelper.SourceGeneration
{
    public sealed class SyntaxContextReceiver : ISyntaxContextReceiver
    {

        private readonly string _contextAttributeName;
        private readonly CancellationToken _cancellationToken;


        public SyntaxContextReceiver(string contextAttributeName, CancellationToken cancellationToken)
        {
            _cancellationToken = cancellationToken;
            _contextAttributeName = contextAttributeName;
        }


        public List<Tuple<ClassDeclarationSyntax, SemanticModel>> ContextClassDeclarations { get; private set; }


        private static bool IsTargetSyntaxNodeForGenerator(SyntaxNode node)
        {
            return node is ClassDeclarationSyntax classDeclaration && classDeclaration.AttributeLists.Count > 0;
        }


        private ClassDeclarationSyntax GetTargetForGenerator(GeneratorSyntaxContext context, CancellationToken cancellationToken)
        {
            var classDeclaration = (ClassDeclarationSyntax)context.Node;

            foreach (var attrList in classDeclaration.AttributeLists)
            {
                foreach (var attr in attrList.Attributes)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        return null;
                    }

                    var symbolInfo = context.SemanticModel.GetSymbolInfo(attr, cancellationToken);
                    if (!(symbolInfo.Symbol is IMethodSymbol attrSymbol))
                    {
                        continue;
                    }

                    INamedTypeSymbol attrContainingTypeSymbol = attrSymbol.ContainingType;
                    string fullName = attrContainingTypeSymbol.ToDisplayString();

                    if (fullName == _contextAttributeName)
                    {
                        return classDeclaration;
                    }
                }
            }

            return null;
        }


        public void OnVisitSyntaxNode(GeneratorSyntaxContext context)
        {
            if (IsTargetSyntaxNodeForGenerator(context.Node))
            {
                var declaration = GetTargetForGenerator(context, _cancellationToken);
                if (declaration != null)
                {
                    (ContextClassDeclarations ?? (ContextClassDeclarations = new List<Tuple<ClassDeclarationSyntax, SemanticModel>>())).Add(new Tuple<ClassDeclarationSyntax, SemanticModel>(declaration, context.SemanticModel));
                }
            }
        }
    }
}
